package io.github.doc.action.language.visitor;

import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.project.Project;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.JavaRecursiveElementVisitor;
import com.intellij.psi.JavaTokenType;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementFactory;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiJavaDocumentedElement;
import com.intellij.psi.PsiJavaFile;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.javadoc.PsiDocComment;
import io.github.doc.action.element.JavaClassElement;
import io.github.doc.common.CommentType;
import org.jetbrains.annotations.NotNull;

/**
 * <p>Company: 深圳振瀚信息技术有限公司成都分公司 </p>
 * <p>Description: </p>
 *
 * @author ZH.Team
 * @version 1.0.0
 * @email "mailto:ZH.Team@zhxx.com"
 * @date 2025.01.05 17:35
 * @since y.y.y
 */
public class JavaFileVisitor extends AbstractTemplateVisitor<PsiJavaFile, PsiElementFactory> {


    /**
     * Element factory
     */
    private final PsiElementFactory elementFactory;

    /**
     * Abstract template visitor
     *
     * @param project project
     * @since y.y.y
     */
    public JavaFileVisitor(Project project) {
        super(project);
        this.elementFactory = JavaPsiFacade.getElementFactory(project);
    }

    /**
     * Support
     *
     * @param file file
     * @return the boolean
     * @since y.y.y
     */
    @Override
    public boolean support(PsiFile file) {
        return file instanceof PsiJavaFile;
    }

    /**
     * Gets element factory *
     *
     * @return the element factory
     * @since y.y.y
     */
    @Override
    public PsiElementFactory getElementFactory() {
        return this.elementFactory;
    }

    /**
     * Generate file element visitor
     *
     * @param psiFile     psi file
     * @param actionEvent action event
     * @return the psi element visitor
     * @since y.y.y
     */
    @Override
    public PsiElementVisitor generateFileElementVisitor(PsiJavaFile psiFile, AnActionEvent actionEvent) {
        return new JavaRecursiveElementVisitor() {

            /**
             * Visit class
             *
             * @param aClass a class
             * @since y.y.y
             */
            @Override
            public void visitClass(@NotNull PsiClass aClass) {
                super.visitClass(aClass);
            }

            /**
             * Visit field
             *
             * @param field field
             * @since y.y.y
             */
            @Override
            public void visitField(@NotNull PsiField field) {
                super.visitField(field);
            }

            /**
             * Visit method
             *
             * @param method method
             * @since y.y.y
             */
            @Override
            public void visitMethod(@NotNull PsiMethod method) {
                super.visitMethod(method);
            }

        };
    }

    /**
     * 元素访问
     *
     * @param psiFile     psi file
     * @param actionEvent action event
     * @return the psi element visitor
     * @since y.y.y
     */
    @Override
    public PsiElementVisitor generateElementVisitor(PsiJavaFile psiFile, AnActionEvent actionEvent) {
        return new JavaRecursiveElementVisitor() {
            /**
             * Visit element
             *
             * @param element element
             * @since y.y.y
             */
            @Override
            public void visitElement(@NotNull PsiElement element) {
                // 获取选中的元素
                PsiElement selectedElement = actionEvent.getData(CommonDataKeys.PSI_ELEMENT);
                if (selectedElement == null) {
                    return;
                }
                if (selectedElement instanceof PsiMethod psiMethod) {
                    this.visitMethod(psiMethod);
                }

                if (selectedElement instanceof PsiClass psiClass) {
                    this.visitClass(psiClass);
                }

                if (selectedElement instanceof PsiField psiField) {
                    this.visitField(psiField);
                }
            }

            /**
             * Visit method
             *
             * @param method method
             * @since y.y.y
             */
            @Override
            public void visitMethod(@NotNull PsiMethod method) {
            }

            /**
             * Visit class
             *
             * @param aClass a class
             * @since y.y.y
             */
            @Override
            public void visitClass(@NotNull PsiClass aClass) {
                JavaFileVisitor.this.generatorClassDoc(aClass);
            }

            /**
             * Visit field
             *
             * @param field field
             * @since y.y.y
             */
            @Override
            public void visitField(@NotNull PsiField field) {
                super.visitField(field);
            }
        };
    }

    /**
     * Delete file element visitor
     *
     * @param psiFile     psi file
     * @param actionEvent action event
     * @return the psi element visitor
     * @since y.y.y
     */
    @Override
    public PsiElementVisitor deleteFileElementVisitor(PsiJavaFile psiFile, AnActionEvent actionEvent) {
        return new JavaRecursiveElementVisitor() {

            /**
             * Visit class
             *
             * @param clz clz
             * @since y.y.y
             */
            @Override
            public void visitClass(@NotNull PsiClass clz) {
                super.visitClass(clz);
                JavaFileVisitor.this.deleteComments(clz);
            }

            /**
             * Visit field
             *
             * @param field field
             * @since y.y.y
             */
            @Override
            public void visitField(@NotNull PsiField field) {
                super.visitField(field);
                JavaFileVisitor.this.deleteComments(field);
            }

            /**
             * Visit method
             *
             * @param method method
             * @since y.y.y
             */
            @Override
            public void visitMethod(@NotNull PsiMethod method) {
                super.visitMethod(method);
                JavaFileVisitor.this.deleteComments(method);
            }
        };
    }

    /**
     * Delete element visitor
     *
     * @param psiFile     psi file
     * @param actionEvent action event
     * @return the psi element visitor
     * @since y.y.y
     */
    @Override
    public PsiElementVisitor deleteElementVisitor(PsiJavaFile psiFile, AnActionEvent actionEvent) {
        return new JavaRecursiveElementVisitor() {
            /**
             * Visit element
             *
             * @param element element
             * @since y.y.y
             */
            @Override
            public void visitElement(@NotNull PsiElement element) {
                // 获取选中的元素
                PsiElement selectedElement = actionEvent.getData(CommonDataKeys.PSI_ELEMENT);
                // 如果选中的元素为空，调用IDEA的信息弹窗提醒选中元素
                if (selectedElement == null) {
                    Notification notification = new Notification("EasyDoc",
                            "Warn",
                            "请选择一个Java元素",
                            NotificationType.ERROR);
                    Notifications.Bus.notify(notification);
                    return;
                }
                JavaFileVisitor.this.deleteComments(selectedElement);
            }
        };
    }

    /**
     * 生成类注释
     *
     * @since y.y.y
     */
    private String generatorClassDoc(PsiClass psiClass) {
        String psiClassName = psiClass.getName();
        // 将类名按照英文单词的格式进行分割

        JavaClassElement javaClassElement = JavaClassElement.builder()
                .psiElement(psiClass)
                .className(psiClassName)
                .build();
        return super.generateTemplate(javaClassElement, CommentType.CLASS);
    }

    /**
     * 删除元素的注释信息
     *
     * @param element element
     * @since y.y.y
     */
    private void deleteComments(PsiElement element) {
        if (element == null) {
            return;
        }
        if (element instanceof PsiJavaDocumentedElement documentedElement) {
            PsiDocComment comment = documentedElement.getDocComment();
            if (comment != null) {
                comment.delete();
            }
        }
        // 删除行注释
        PsiElement[] children = element.getChildren();
        for (PsiElement child : children) {
            if (child instanceof PsiComment && ((PsiComment) child).getTokenType() == JavaTokenType.END_OF_LINE_COMMENT) {
                child.delete();
            }
        }
    }

}
